RTTI
Runtime Type Information
好吧,时隔多日我又来啃这块骨头了;
RTTI顾名思义 运行时类型信息;编译的时候不知道,只有当具体运行时才知道是什么类型信息;Java编程思想好像也没说是怎么具体实现的;我也只能管中窥豹了;
首先,我们知道多态,那么多态是啥呢?
维基百科说:
多态也可定义为“一种将不同的特殊行为和单个泛化记号相关联的能力”
这就让我想起了继承关系;不论是哪个子类都可以用父类表示;编译时是父类,运行时就变成子类了;这就是RTTI了;厉害吧;
Class对象
首先想知道Class对象是什么,必须清楚类,类实例化之后形成一个对象;
这是我们常见的:类和对象?那么类是什么?对于虚拟机来说,他怎么区别这个对象和那个对象不一样呢? 这就靠类对象了;通过类对象,我们就知道“类型”;
举个例子;我们说狮子,一般是一个名词,指代一种生物,某个狮子就是狮子这个类的实例化;但是我们的大脑,社会上的文字,是要储存狮子的定义的;这样你知道Class对象是什么了吧;
class调用顺序
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Candy { public Candy() { System.out.println("ccandy"); } { System.out.println("no static"); } static { System.out.println("loading Cnady"); } }
|
1 2 3 4 5 6 7 8 9 10 11
| public class SweetShop { public static void main(String [] arg) throws ClassNotFoundException { new Candy(); Class a =Class.forName("Class.Gum"); } } output: loading Cnady no static ccandy loading Gun
|
类字面常量
想调用类有三种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException { Class class1=ReflectDemo.class; System.out.println(class1.getName()); ReflectDemo demo2= new ReflectDemo(); Class c2 = demo2.getClass(); System.out.println(c2.getName()); Class class3 = Class.forName("com.tengj.reflect.ReflectDemo"); System.out.println(class3.getName()); } }
|
第一种的Code.class又叫做类字面常量,好处是不会直接初始化class对象,仅仅是加载;
使用类的准备工作有
- 加载
- 链接
- 初始化,由于java很懒,所以都是啥时候用到啥时候加载,所以直接的forName就有点不好玩了;初始化要延迟到静态方法被调用,(所以构造函数也是静态方法),或者非常数讲台域被引用的时候;
泛化的class引用
- 简单地说就是class引用带了类型,只接受这种,或者一部分的class对象;
- instance与instanceof,简单说一个要比名字,另一个比的是class对象,对象可以动态传参,所以就方便许多;
- instance和class比较时的区别 instance会考虑继承;即:麻雀是鸟,但是class不会这么比,麻雀!=鸟;
反射
其实就是通过class对象来获取类中的相关内容比如获取一个方法
以下代码来源:”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| public class Person { private String name; private int age; private String msg="hello wrold"; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Person() { } private Person(String name) { this.name = name; System.out.println(name); } public void fun() { System.out.println("fun"); } public void fun(String name,int age) { System.out.println("我叫"+name+",今年"+age+"岁"); } } public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Object o = c.newInstance(); Method method = c.getMethod("fun", String.class, int.class); method.invoke(o, "tengj", 10); } catch (Exception e) { e.printStackTrace(); } } }
|
或者获取方法组
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Method[] methods = c.getDeclaredMethods(); for(Method m:methods){ String methodName= m.getName(); System.out.println(methodName); } } catch (Exception e) { e.printStackTrace(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Field field = c.getDeclaredField("msg"); Object o = c.newInstance(); field.setAccessible(true); Object msg = field.get(o); System.out.println(msg); } catch (Exception e) { e.printStackTrace(); } } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ReflectDemo { public static void main(String[] args){ try { Class c = Class.forName("com.tengj.reflect.Person"); Constructor constructor = c.getDeclaredConstructor(String.class); constructor.setAccessible(true); constructor.newInstance("tengj"); } catch (Exception e) { e.printStackTrace(); } } }
|
ps:无关思想的细节就不要深究了;
接口与类型信息
1.通过使用反射,即使实现包的访问权限,仍旧可以到达并调用所有方法,甚至是private方法。如果知道方法名,就可以在其Method对象上调用setAccessible(true),然后通过invoke()方法来使用该方法。
2.final域实际上在遭遇修改时是安全的。运行时系统会在不抛异常的情况下接受任何修改尝试,但实际上不会发生任何修改